package org.notabug.lifeuser.moviedb.activity;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.preference.PreferenceManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextPaint;
import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RatingBar;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.DatePicker;

import com.squareup.picasso.Picasso;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.notabug.lifeuser.moviedb.ConfigHelper;
import org.notabug.lifeuser.moviedb.MovieDatabaseHelper;
import org.notabug.lifeuser.moviedb.NotifyingScrollView;
import org.notabug.lifeuser.moviedb.R;
import org.notabug.lifeuser.moviedb.adapter.SimilarMovieBaseAdapter;
import org.notabug.lifeuser.moviedb.adapter.CastBaseAdapter;
import org.notabug.lifeuser.moviedb.fragment.ListFragment;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.text.SimpleDateFormat;

import java.lang.Runnable;

/**
* This class provides all the details about the shows.
* It also manages personal show data.
*/
public class DetailActivity extends BaseActivity {

	private RecyclerView castView;
    private RecyclerView crewView;
	private CastBaseAdapter castAdapter;
    private CastBaseAdapter crewAdapter;
	private ArrayList<JSONObject> castArrayList;
    private ArrayList<JSONObject> crewArrayList;

	private RecyclerView similarMovieView;
	private SimilarMovieBaseAdapter similarMovieAdapter;
	private ArrayList<JSONObject> similarMovieArrayList;

	private Drawable mToolbarBackgroundDrawable;
	private Toolbar toolbar;

	private SQLiteDatabase database;
	private MovieDatabaseHelper databaseHelper;
	private int movieId;
	private String movieImageId;
	private String moviePosterId;
	private String voteAverage;
	private String movieName;
	private Integer totalEpisodes;

	private float amountStars;
	private boolean isMovie = true;

	private ImageView movieImage;
	private TextView movieTitle;
	private ImageView moviePoster;
	private TextView movieGenres;
	private TextView movieStartDate;
	private TextView movieFinishDate;
	private TextView movieRewatched;
	private TextView movieEpisodes;
	private RatingBar movieRating;
	private TextView movieDescription;

	private JSONObject jMovieObject;
	private String genres;

	private String startDate;
	private String finishDate;

	private int defaultButton;

    private Activity mActivity;

	private boolean added = false;

	private SpannableString showTitle;
	private AlphaForegroundColorSpan alphaForegroundColorSpan;

	private SharedPreferences preferences;
	private final static String CAST_VIEW_PREFERENCE = "key_show_cast";
	private final static String CREW_VIEW_PREFERENCE = "key_show_crew";
	private final static String SIMILAR_MOVIE_VIEW_PREFERENCE = "key_show_similar_movies";
	private final static String SHOW_SAVE_DIALOG_PREFERENCE = "key_show_save_dialog";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

        // Set the proper layout.
		setContentView(R.layout.activity_detail);
		setNavigationDrawer();
		setBackButtons();

		// Set a transparent background for the toolbar that 
        // becomes less transparent when scrolling down.
		mToolbarBackgroundDrawable = new ColorDrawable(ContextCompat
				.getColor(getApplicationContext(), R.color.colorPrimary));
		mToolbarBackgroundDrawable.setAlpha(0);
		
		toolbar = (Toolbar) findViewById(R.id.toolbar);
		toolbar.setBackgroundDrawable(mToolbarBackgroundDrawable);

		// Make the transparency dependent on how far the user scrolled down.
		NotifyingScrollView notifyingScrollView = (NotifyingScrollView)
				findViewById(R.id.scrollView);
		notifyingScrollView.setOnScrollChangedListener(mOnScrollChangedListener);

		if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
			mToolbarBackgroundDrawable.setCallback(drawableCallback);
		}

        // Create a variable with the application context that can be used
        // when data is retrieved.
        mActivity = this;

		// RecyclerView to display the cast of the show.
		castView = (RecyclerView) findViewById(R.id.castRecyclerView);
		castView.setHasFixedSize(true); // Improves performance (if size is static)

		LinearLayoutManager castLinearLayoutManager = new LinearLayoutManager(this, 
				LinearLayoutManager.HORIZONTAL, false);
		castView.setLayoutManager(castLinearLayoutManager);

		// RecyclerView to display the crew of the show.
        crewView = (RecyclerView) findViewById(R.id.crewRecyclerView);
        crewView.setHasFixedSize(true); // Improves performance (if size is static)

        LinearLayoutManager crewLinearLayoutManager = new LinearLayoutManager(this,
                LinearLayoutManager.HORIZONTAL, false);
        crewView.setLayoutManager(crewLinearLayoutManager);

		// RecyclerView to display similar shows to this one.
		similarMovieView = (RecyclerView) findViewById(R.id.movieRecyclerView);
		similarMovieView.setHasFixedSize(true); // Improves performance (if size is static)
		LinearLayoutManager movieLinearLayoutManager = new LinearLayoutManager(this,
				LinearLayoutManager.HORIZONTAL, false);
		similarMovieView.setLayoutManager(movieLinearLayoutManager);

		// Make the views invisible if the user collapsed the view.
		preferences = PreferenceManager.getDefaultSharedPreferences(this);

		if(!preferences.getBoolean(CAST_VIEW_PREFERENCE, false)) {
			castView.setVisibility(View.GONE);

			TextView castTitle = (TextView) findViewById(R.id.castTitle);
			castTitle.setVisibility(View.GONE);
		}

		if(!preferences.getBoolean(CREW_VIEW_PREFERENCE, false)) {
			crewView.setVisibility(View.GONE);

			TextView crewTitle = (TextView) findViewById(R.id.crewTitle);
			crewTitle.setVisibility(View.GONE);
		}

		if(!preferences.getBoolean(SIMILAR_MOVIE_VIEW_PREFERENCE, false)) {
			similarMovieView.setVisibility(View.GONE);

			TextView similarMovieTitle = (TextView) findViewById(R.id.similarMovieTitle);
			similarMovieTitle.setVisibility(View.GONE);
		}

		// Get the views from the layout.
		movieImage = (ImageView) findViewById(R.id.movieImage);
		movieTitle = (TextView) findViewById(R.id.movieTitle);
		moviePoster = (ImageView) findViewById(R.id.moviePoster);
		movieGenres = (TextView) findViewById(R.id.movieGenres);
		movieStartDate = (TextView) findViewById(R.id.movieStartDate);
		movieFinishDate = (TextView) findViewById(R.id.movieFinishDate);
		movieRewatched = (TextView) findViewById(R.id.movieRewatched);
		movieEpisodes = (TextView) findViewById(R.id.movieEpisodes);
		movieRating = (RatingBar) findViewById(R.id.movieRating);
		movieDescription = (TextView) findViewById(R.id.movieDescription);

		// Get the movieObject from the intent that contains the necessary
        // data to display the right movie and related RecyclerViews. 
        // Send the JSONObject to setMovieData() so all the data 
        // will be displayed on the screen.
		Intent intent = getIntent();
		isMovie = intent.getBooleanExtra("isMovie", true);
		try {
			setMovieData(new JSONObject(intent.getStringExtra("movieObject")));
			jMovieObject = new JSONObject(intent.getStringExtra("movieObject"));

            // Set the adapter with the (still) empty ArrayList.
			castArrayList = new ArrayList<JSONObject>();
			castAdapter = new CastBaseAdapter(castArrayList, getApplicationContext());
			castView.setAdapter(castAdapter);

            // Set the adapter with the (still) empty ArrayList.
            crewArrayList = new ArrayList<JSONObject>();
            crewAdapter = new CastBaseAdapter(crewArrayList, getApplicationContext());
            crewView.setAdapter(crewAdapter);

            // Set the adapter with the (still) empty ArrayList.
			similarMovieArrayList = new ArrayList<JSONObject>();
			similarMovieAdapter = new SimilarMovieBaseAdapter(similarMovieArrayList,
					getApplicationContext());
			similarMovieView.setAdapter(similarMovieAdapter);
		} catch(JSONException e) {
			e.printStackTrace();
		}

		// Get the cast and crew for the CastListAdapter and get the movies for the MovieListAdapter.
		new CastList().execute();
		new SimilarMovieList().execute();

		// Load movie details.
		new MovieDetails().execute();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.save_menu, menu);

		databaseHelper = new MovieDatabaseHelper(getApplicationContext());
		database = databaseHelper.getWritableDatabase();
		databaseHelper.onCreate(database);

		// Check if the show is already in the database.
		Cursor cursor = database.rawQuery("SELECT * FROM " +
				MovieDatabaseHelper.TABLE_MOVIES +
				" WHERE " + MovieDatabaseHelper.COLUMN_MOVIES_ID +
				"=" + movieId + " LIMIT 1", null);

        // If the show is in the database, display a filled in star as icon.
		if (cursor.getCount() > 0) {
			// A record has been found
			MenuItem item = menu.findItem(R.id.action_save);
			item.setIcon(R.drawable.ic_star);
			added = true;
		}
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(final MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();

        // Add or remove the show from the database.
		if (id == R.id.action_save) {
			databaseHelper = new MovieDatabaseHelper(getApplicationContext());
			database = databaseHelper.getWritableDatabase();
			databaseHelper.onCreate(database);
			if (added) {
				// Remove the show from the database.
				database.delete(MovieDatabaseHelper.TABLE_MOVIES,
						MovieDatabaseHelper.COLUMN_MOVIES_ID + "=" + movieId, null);
				added = false;
				item.setIcon(R.drawable.ic_star_border);
				ListFragment.databaseUpdate();
			} else {
				final ContentValues showValues = new ContentValues();

                // Only show the dialog is the user specified so in the preferences.
				if (preferences.getBoolean(SHOW_SAVE_DIALOG_PREFERENCE, false)) {

					// Ask in which category the show should be placed.
					final AlertDialog.Builder categoriesDialog = new AlertDialog.Builder(this);
					categoriesDialog.setTitle(getString(R.string.category_picker));
					categoriesDialog.setItems(R.array.categories, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							showValues.put(MovieDatabaseHelper.COLUMN_CATEGORIES, getCategoryNumber(which));

							addMovieToDatabase(showValues, item);
						}
					});

					categoriesDialog.show();
				} else {
                    // If no dialog is shown, add the show to the default category.
					showValues.put(MovieDatabaseHelper.COLUMN_CATEGORIES, MovieDatabaseHelper.CATEGORY_WATCHING);
					addMovieToDatabase(showValues, item);
				}
			}
		}

		return super.onOptionsItemSelected(item);
	}

    /**
     * Returns the category number when supplied with
     * the category string array index.
     * @param index the position in the string array.
     * @return the category number of the specified position.
     */
	public static int getCategoryNumber(int index) {
		switch(index) {
			case 0:
				return MovieDatabaseHelper.CATEGORY_WATCHING;
			case 1:
				return MovieDatabaseHelper.CATEGORY_PLAN_TO_WATCH;
			case 2:
				return MovieDatabaseHelper.CATEGORY_WATCHED;
			case 3:
				return MovieDatabaseHelper.CATEGORY_ON_HOLD;
			case 4:
				return MovieDatabaseHelper.CATEGORY_DROPPED;
			default:
				return MovieDatabaseHelper.CATEGORY_WATCHING;
		}
	}

    /**
     * Returns the category number when supplied with 
     * the category string.
     * @param category the name of the category in snake case style.
     * @return the category number of the specified category string.
     */
	public static int getCategoryNumber(String category) {
		switch(category) {
			case "watching":
				return MovieDatabaseHelper.CATEGORY_WATCHING;
			case "plan_to_watch":
				return MovieDatabaseHelper.CATEGORY_PLAN_TO_WATCH;
			case "watched":
				return MovieDatabaseHelper.CATEGORY_WATCHED;
			case "on_hold":
				return MovieDatabaseHelper.CATEGORY_ON_HOLD;
			case "dropped":
				return MovieDatabaseHelper.CATEGORY_DROPPED;
			default:
				return MovieDatabaseHelper.CATEGORY_WATCHING;
		}
	}

    /**
     * Adds all necessary values to the ContentValues
     * and then inserts it into the database.
     * @param showValues the ContentValuese with the already specified values.
     * @param item the menu item that will be replaced with a filled in star.
     */
	private void addMovieToDatabase(ContentValues showValues, MenuItem item) {
		// Add the show to the database.
		try {
            // Put the necessary values into ContentValues object.
			showValues.put(MovieDatabaseHelper.COLUMN_MOVIES_ID,
					Integer.parseInt(jMovieObject.getString("id")));
			showValues.put(MovieDatabaseHelper.COLUMN_IMAGE,
					jMovieObject.getString("backdrop_path"));
			showValues.put(MovieDatabaseHelper.COLUMN_ICON,
					jMovieObject.getString("poster_path"));
			String title = (isMovie) ? "title" : "name";
			showValues.put(MovieDatabaseHelper.COLUMN_TITLE, jMovieObject.getString(title));
			showValues.put(MovieDatabaseHelper.COLUMN_SUMMARY, jMovieObject.getString("overview"));
			showValues.put(MovieDatabaseHelper.COLUMN_GENRES, genres);
			showValues.put(MovieDatabaseHelper.COLUMN_GENRES_IDS,
					jMovieObject.getString("genre_ids"));
			showValues.put(MovieDatabaseHelper.COLUMN_MOVIE, isMovie);
			showValues.put(MovieDatabaseHelper.COLUMN_RATING,
					jMovieObject.getString("vote_average"));
			String releaseDate = (isMovie) ? "release_date" : "first_air_date";
			showValues.put(MovieDatabaseHelper.COLUMN_RELEASE_DATE,
					jMovieObject.getString(releaseDate));

            // Insert the show into the database.
			database.insert(MovieDatabaseHelper.TABLE_MOVIES, null, showValues);

            // Inform the user of the addition to the database
            // and change the boolean in order to change the MenuItem's behaviour.
			added = true;
			item.setIcon(R.drawable.ic_star);
			if (isMovie) {
				Toast.makeText(getApplicationContext(), getResources().getString(R.string.movie_added), Toast.LENGTH_SHORT).show();
			} else {
				Toast.makeText(getApplicationContext(), getResources().getString(R.string.series_added), Toast.LENGTH_SHORT).show();
			}
		} catch (JSONException je) {
			je.printStackTrace();
			Toast.makeText(this, getResources().getString(R.string.show_added_error),
					Toast.LENGTH_SHORT).show();
		}

        // Update the ListFragment to include the newly added show.
		ListFragment.databaseUpdate();
	}

	@Override
	public void onBackPressed() {
		LinearLayout editShowDetails = (LinearLayout) findViewById(R.id.editShowDetails);

		if(editShowDetails.getVisibility() != View.GONE) {
			// Clear the focus (in case it has the focus)
			// so the content will be saved when the user leaves.
			Spinner categoriesView = (Spinner) findViewById(R.id.categories);
			EditText timesWatched = (EditText) findViewById(R.id.timesWatched);
			EditText episodesSeen = (EditText) findViewById(R.id.episodesSeen);
			EditText showRating = (EditText) findViewById(R.id.showRating);

			categoriesView.clearFocus();
			timesWatched.clearFocus();
			episodesSeen.clearFocus();
			showRating.clearFocus();
		}

		setResult(RESULT_CANCELED);
		finish();
	}

    /**
     * Checks if the current data is different than the data from the 
     * specified JSONObject. If that's the case, replace the data with the
     * data from the specified JSONObject.
     * @param movieObject JSONObject with the information about the show.
     */
	private void setMovieData(JSONObject movieObject) {
		// Check if movieObject values differ from the current values,
		// if they do, use the movieObject values.
		try {
			// Set the movieId
			movieId = Integer.parseInt(movieObject.getString("id"));

			// Due to the difficulty of comparing images (or rather,
			// this can be a really slow process) the id of the image is
			// saved as class variable for easy comparison.
			if(movieObject.has("backdrop_path") && 
					!movieObject.getString("backdrop_path").equals(movieImageId)) {
				Picasso.with(this).load("https://image.tmdb.org/t/p/w780" + 
						movieObject.getString("backdrop_path"))
						.into(movieImage);

				Animation animation = AnimationUtils.loadAnimation(
						getApplicationContext(), R.anim.fade_in);
				movieImage.startAnimation(animation);

				// Set the old imageId to the new one.
				movieImageId = movieObject.getString("backdrop_path");
			}

			// Same goes for the movie poster of course.
			if(movieObject.has("poster_path") && 
					!movieObject.getString("poster_path").equals(moviePosterId)) {
				Picasso.with(this).load("https://image.tmdb.org/t/p/w500" +
						movieObject.getString("poster_path"))
						.into(moviePoster);

				// Set the old posterId to the new one.
				moviePosterId = movieObject.getString("poster_path");
			}

			// Check if it is a movie or a TV series.
			String title = (movieObject.has("title")) ? "title" : "name";

			if(movieObject.has(title) && 
					!movieObject.getString(title).equals(movieTitle
					.getText().toString())) {
				movieTitle.setText(movieObject.getString(title));

				// Initialise global variables (will become visible when scrolling down).
				showTitle = new SpannableString(movieObject.getString(title));
				alphaForegroundColorSpan = new AlphaForegroundColorSpan(0xffffffff);
			}

			// The rating also uses a class variable for the same reason
			// as the image.
			databaseHelper = new MovieDatabaseHelper(getApplicationContext());
			database = databaseHelper.getWritableDatabase();

			databaseHelper.onCreate(database);

            // Retrieve and present saved data of the show.
			Cursor cursor = database.rawQuery("SELECT * FROM " + 
					MovieDatabaseHelper.TABLE_MOVIES + 
					" WHERE " + MovieDatabaseHelper.COLUMN_MOVIES_ID + 
					"=" + movieId + " LIMIT 1", null);
			if(cursor.getCount() > 0) {
				cursor.moveToFirst();
				// Set the rating to the personal rating of the user.
				movieRating.setRating( cursor.getFloat(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_RATING)) / 2);

				// If the database has a start date, use it, otherwise print unknown.
				if(!cursor.isNull(cursor.getColumnIndex
						(MovieDatabaseHelper.COLUMN_PERSONAL_START_DATE))
						&& !cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_START_DATE)).equals("")) {
					startDate = cursor.getString(
							cursor.getColumnIndex(MovieDatabaseHelper
									.COLUMN_PERSONAL_START_DATE));
					movieStartDate.setText(getString(R.string.start_date) + startDate);
				} else {
					movieStartDate.setText(getString(R.string.start_date_unknown));
				}

				// If the database has a finish date, use it, otherwise print unknown.
				if(!cursor.isNull(cursor.getColumnIndex
						(MovieDatabaseHelper.COLUMN_PERSONAL_FINISH_DATE))
						&& !cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_FINISH_DATE)).equals("")) {
					finishDate = cursor.getString(
							cursor.getColumnIndex(MovieDatabaseHelper
									.COLUMN_PERSONAL_FINISH_DATE));
					movieFinishDate.setText(getString(R.string.finish_date) + finishDate);
				} else {
					movieFinishDate.setText(getString(R.string.finish_date_unknown));
				}

				// If the database has a rewatched count, use it, otherwise it is 0.
				int watched = 0;
				if(!cursor.isNull(cursor.getColumnIndex
						(MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED))
						&& !cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED)).equals("")) {
					watched = cursor.getInt(cursor.getColumnIndex(MovieDatabaseHelper
							.COLUMN_PERSONAL_REWATCHED));
				} else if (cursor.getInt(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_CATEGORIES)) == 1) {
					watched = 1;
				}
				movieRewatched.setText(getString(R.string.times_watched) + watched);

				// If the database has an episodes seen count, use it, otherwise it is 0.
				// Only make "episodes seen" visible for TV shows.
				if (!isMovie) {
					int episodeCount = 0;

					// Get the total amount of episodes (of all seasons).
					JSONArray seasonArray = movieObject.getJSONArray("seasons");
					if (seasonArray != null) {
						if (seasonArray.length() > 1) {
							totalEpisodes = 0;
							// If there are more seasons, season 0 mostly refers to Specials.
							// Specials (and other extras) don't count as episodes.
							// (which is also the reason that number_of_episodes is not used)
							for (int i = 1; i < seasonArray.length(); i++) {
								if (seasonArray.get(i) != null) {
									totalEpisodes += ((JSONObject) seasonArray.get(i)).getInt("episode_count");
								}
							}
						} else {
							totalEpisodes = ((JSONObject) seasonArray.get(0)).getInt("episode_count");
						}
					}

                    // If there is a personal episode count available,
                    // set the episodeCount equal to it. If the show is marked
                    // as "watched" then that implies that all episodes have 
                    // been seen and therefore episodeCount is equal to totalEpisodes.
					if (!cursor.isNull(cursor.getColumnIndex
							(MovieDatabaseHelper.COLUMN_PERSONAL_EPISODES))
							&& !cursor.getString(cursor.getColumnIndex(
							MovieDatabaseHelper.COLUMN_PERSONAL_EPISODES)).equals("")) {
						episodeCount = cursor.getInt(
								cursor.getColumnIndex(MovieDatabaseHelper
								.COLUMN_PERSONAL_EPISODES));
					} else if (cursor.getInt(cursor.getColumnIndex(
							MovieDatabaseHelper.COLUMN_CATEGORIES)) == 1) {
						episodeCount = totalEpisodes;
					}
					movieEpisodes.setText(getString(R.string.episodes_seen) + episodeCount + "/"
							+ totalEpisodes);

                    // Make the row visible once the correct values are set.
					TableRow episodesSeenRow = (TableRow) findViewById(R.id.episodesSeen).getParent();
					episodesSeenRow.setVisibility(View.VISIBLE);
					movieEpisodes.setVisibility(View.VISIBLE);
				}

				// Make all the views visible (if the show is in the database).
				movieStartDate.setVisibility(View.VISIBLE);
				movieFinishDate.setVisibility(View.VISIBLE);
				movieRewatched.setVisibility(View.VISIBLE);

				// Make it possible to change the values.
				ImageView editIcon = (ImageView) findViewById(R.id.editIcon);
				editIcon.setVisibility(View.VISIBLE);
			} else if(movieObject.has("vote_average") && 
					!movieObject.getString("vote_average").equals(voteAverage)) {
				// Set the avarage (non-personal) rating (if it isn't the same).
				movieRating.setRating(Float.parseFloat(movieObject
						.getString("vote_average")) / 2);
			}

			// If the overview (summary) is different in the new dataset, change it.
			if(movieObject.has("overview") && 
					!movieObject.getString("overview").equals(movieDescription
					.getText().toString()) && !movieObject.getString("overview")
					.equals("") && !movieObject.getString("overview").equals("null")) {
				movieDescription.setText(movieObject.getString("overview"));
				if(movieObject.getString("overview").equals("")) {
					new MovieDetails().execute("true");
				}
			}

			// Set the genres
			if(movieObject.has("genre_ids")) {
				// This works a bit different, 
				// the ids will be converted to genres first after that
				// the new text with genres will be compared to the old one.

				// Remove the [ and ] from the String
				String genreIds = movieObject.getString("genre_ids")
						.substring(1, movieObject.getString("genre_ids")
						.length() - 1);

				// Split the String with the ids and set them into an array.
				String[] genreArray = genreIds.split(",");

				// Get the sharedPreferences
				SharedPreferences sharedPreferences = getApplicationContext()
						.getSharedPreferences("GenreList", Context.MODE_PRIVATE);

				// Add all the genres in one String.
				String genreNames = "";
				for(int i = 0; i < genreArray.length; i++) {
					genreNames += ", " + sharedPreferences
							.getString(genreArray[i], genreArray[i]);
				}

				// Remove the first ", " from the String and set the text.
				movieGenres.setText(genreNames.substring(2));
				genres = genreNames.substring(2);
			}

			cursor.close();
		} catch(JSONException e) {
			e.printStackTrace();
		}
	}

    /**
     * Makes the showDetails layout invisible and the editShowDetails visible
     * (or the other way around). 
     * @param view */
	public void editDetails(View view) {
		final LinearLayout showDetails, editShowDetails;
		showDetails = (LinearLayout) findViewById(R.id.showDetails);
		editShowDetails = (LinearLayout) findViewById(R.id.editShowDetails);
		ImageView editIcon = (ImageView) findViewById(R.id.editIcon);

		final EditText episodesSeenView = (EditText) findViewById(R.id.episodesSeen);
		final EditText timesWatchedView = (EditText) findViewById(R.id.timesWatched);
		final EditText showRating = (EditText) findViewById(R.id.showRating);

		if(editShowDetails.getVisibility() == View.GONE) {
			fadeOutAndHideAnimation(showDetails);
			showDetails.getAnimation().setAnimationListener(new Animation.AnimationListener() {
				@Override
				public void onAnimationStart(Animation animation) {
					fadeInAndShowAnimation(editShowDetails);
					updateEditShowDetails();
					showDetails.setVisibility(View.GONE);
				}

				@Override
				public void onAnimationEnd(Animation animation) {

				}

				@Override
				public void onAnimationRepeat(Animation animation) {

				}
			});

			editIcon.setImageResource(R.drawable.ic_check_black_24dp);

			// Listen for changes to the categories.
			Spinner categoriesView = (Spinner) findViewById(R.id.categories);
			categoriesView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
				@Override
				public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
					// Save the category to the database
					ContentValues showValues = new ContentValues();
					database = databaseHelper.getWritableDatabase();
					Cursor cursor = database.rawQuery("SELECT * FROM " +
							MovieDatabaseHelper.TABLE_MOVIES +
							" WHERE " + MovieDatabaseHelper.COLUMN_MOVIES_ID +
							"=" + movieId + " LIMIT 1", null);
					cursor.moveToFirst();

					// Check if the show is already watched and if the user changed the category.
					if (getCategoryNumber(position) == 1
							&& cursor.getInt(cursor.getColumnIndex(
							MovieDatabaseHelper.COLUMN_CATEGORIES))
							!= getCategoryNumber(position)) {
						if (totalEpisodes != null) {
							showValues.put(MovieDatabaseHelper.COLUMN_PERSONAL_EPISODES,
									totalEpisodes);
							episodesSeenView.setText(totalEpisodes.toString());
						}

						// If the user hasn't set their own watched value, automatically set it.
						Integer timesWatchedCount = cursor.getInt(cursor.getColumnIndex(
								MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED));
						if (timesWatchedCount == null || timesWatchedCount == 0) {
							showValues.put(MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED,
									1);
							timesWatchedView.setText("1");
						}
					}

					showValues.put(MovieDatabaseHelper.COLUMN_CATEGORIES,
							getCategoryNumber(position));
					database.update(MovieDatabaseHelper.TABLE_MOVIES, showValues,
							MovieDatabaseHelper.COLUMN_MOVIES_ID + "=" + movieId, null);
					database.close();
				}

				@Override
				public void onNothingSelected(AdapterView<?> parent) {
					// Do nothing
				}
			});

			// Listen to changes to the EditText.
			timesWatchedView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
				@Override
				public void onFocusChange(View v, boolean hasFocus) {
					if(!hasFocus) {
						// Save the number to the database
						ContentValues showValues = new ContentValues();
						int timesWatched = Integer.parseInt(timesWatchedView.getText().toString());
						showValues.put(MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED,
								timesWatched);

						database = databaseHelper.getWritableDatabase();
						databaseHelper.onCreate(database);
						database.update(MovieDatabaseHelper.TABLE_MOVIES, showValues,
								MovieDatabaseHelper.COLUMN_MOVIES_ID + "=" + movieId, null);

						database.close();

						// Update the view
						movieRewatched.setText(getString(R.string.change_watched_times) +
								Integer.toString(timesWatched));
					}
				}
			});

			// Listen to changes to the EpisodesSeen EditText.
			episodesSeenView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
				@Override
				public void onFocusChange(View v, boolean hasFocus) {
					if (!hasFocus) {
						// Save the number to the database
						ContentValues showValues = new ContentValues();
						int episodesSeen = Integer.parseInt(episodesSeenView.getText().toString());
						showValues.put(MovieDatabaseHelper.COLUMN_PERSONAL_EPISODES,
								episodesSeen);

						database = databaseHelper.getWritableDatabase();
						databaseHelper.onCreate(database);
						database.update(MovieDatabaseHelper.TABLE_MOVIES, showValues,
								MovieDatabaseHelper.COLUMN_MOVIES_ID + "=" + movieId, null);

						database.close();

						// Update the view
						movieEpisodes.setText(getString(R.string.episodes_seen) +
								Integer.toString(episodesSeen));
					}
				}
			});

			// Listen to changes to the ShowRating EditText.
			showRating.setOnFocusChangeListener(new View.OnFocusChangeListener() {
				@Override
				public void onFocusChange(View v, boolean hasFocus) {
					if (!hasFocus) {
						// Save the number to the database
						ContentValues showValues = new ContentValues();
						int rating = Integer.parseInt(showRating.getText().toString());

						// Do not allow ratings outside of the range.
						if (rating > 10) {
							rating = 10;
						} else if (rating < 0) {
							rating = 0;
						}
						showValues.put(MovieDatabaseHelper.COLUMN_PERSONAL_RATING, rating);

						database = databaseHelper.getWritableDatabase();
						databaseHelper.onCreate(database);
						database.update(MovieDatabaseHelper.TABLE_MOVIES, showValues,
								MovieDatabaseHelper.COLUMN_MOVIES_ID + "=" + movieId, null);

						database.close();

						// Update the view
						movieRating.setRating((float) rating / 2);
					}
				}
			});
		} else {
			fadeOutAndHideAnimation(editShowDetails);
			editShowDetails.getAnimation().setAnimationListener(new Animation.AnimationListener() {
				@Override
				public void onAnimationStart(Animation animation) {
					fadeInAndShowAnimation(showDetails);
					editShowDetails.setVisibility(View.GONE);
				}

				@Override
				public void onAnimationEnd(Animation animation) {

				}

				@Override
				public void onAnimationRepeat(Animation animation) {

				}
			});

			editIcon.setImageResource(R.drawable.ic_edit_black_24dp);
		}
	}

	private void updateEditShowDetails() {
		database = databaseHelper.getWritableDatabase();
		databaseHelper.onCreate(database);
		Cursor cursor = database.rawQuery("SELECT * FROM " +
				MovieDatabaseHelper.TABLE_MOVIES +
				" WHERE " + MovieDatabaseHelper.COLUMN_MOVIES_ID +
				"=" + movieId + " LIMIT 1", null);

		if (cursor.getCount() <= 0) {
			// No record has been found, the show hasn't been added or an error occurred.
			cursor.close();
		} else {
			cursor.moveToFirst();

			Spinner categories = (Spinner) findViewById(R.id.categories);
			Button startDateButton = (Button) findViewById(R.id.startDateButton);
			Button endDateButton = (Button) findViewById(R.id.endDateButton);
			EditText timesWatched = (EditText) findViewById(R.id.timesWatched);
			EditText episodesSeen = (EditText) findViewById(R.id.episodesSeen);
			EditText showRating = (EditText) findViewById(R.id.showRating);

			// Set the right category.
			switch(cursor.getInt(cursor.getColumnIndex(
					MovieDatabaseHelper.COLUMN_CATEGORIES))) {
				case MovieDatabaseHelper.CATEGORY_PLAN_TO_WATCH:
					categories.setSelection(1);
					break;
				case MovieDatabaseHelper.CATEGORY_WATCHED:
					categories.setSelection(2);
					break;
				case MovieDatabaseHelper.CATEGORY_ON_HOLD:
					categories.setSelection(3);
					break;
				case MovieDatabaseHelper.CATEGORY_DROPPED:
					categories.setSelection(4);
					break;
				default:
					// The "Watching" category will be displayed.
					break;
			}

			if (!cursor.isNull(cursor.getColumnIndex
					(MovieDatabaseHelper.COLUMN_PERSONAL_START_DATE))
					&& !cursor.getString(cursor.getColumnIndex(
					MovieDatabaseHelper.COLUMN_PERSONAL_START_DATE)).equals("")) {
				startDate = cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_START_DATE));
				startDateButton.setText(startDate);
			} else {
				startDateButton.setText("Not set");
			}

			if (!cursor.isNull(cursor.getColumnIndex
					(MovieDatabaseHelper.COLUMN_PERSONAL_FINISH_DATE))
					&& !cursor.getString(cursor.getColumnIndex(
					MovieDatabaseHelper.COLUMN_PERSONAL_FINISH_DATE)).equals("")) {
				finishDate = cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_FINISH_DATE));
				endDateButton.setText(finishDate);
			} else {
				endDateButton.setText("Not set");
			}

			if (!cursor.isNull(cursor.getColumnIndex
					(MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED))
					&& !cursor.getString(cursor.getColumnIndex(
					MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED)).equals("")) {
				timesWatched.setText(cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_REWATCHED
				)));
			} else {
				if (cursor.getInt(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_CATEGORIES)) == 1) {
					timesWatched.setText("1");
				} else {
					timesWatched.setText("0");
				}
			}

			if (!cursor.isNull(cursor.getColumnIndex
					(MovieDatabaseHelper.COLUMN_PERSONAL_EPISODES))
					&& !cursor.getString(cursor.getColumnIndex(
					MovieDatabaseHelper.COLUMN_PERSONAL_EPISODES)).equals("")) {
				episodesSeen.setText(cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_EPISODES
				)));
			} else {
				if (cursor.getInt(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_CATEGORIES)) == 1
						&& totalEpisodes != null) {
					episodesSeen.setText(totalEpisodes.toString());
				} else {
					episodesSeen.setText("0");
				}
			}

			if (!cursor.isNull(cursor.getColumnIndex(
					MovieDatabaseHelper.COLUMN_PERSONAL_RATING))
					&& !cursor.getString(cursor.getColumnIndex(
					MovieDatabaseHelper.COLUMN_PERSONAL_RATING)).equals("")) {
				showRating.setText(cursor.getString(cursor.getColumnIndex(
						MovieDatabaseHelper.COLUMN_PERSONAL_RATING
				)));
			}
		}
		ListFragment.databaseUpdate();
	}

	public void selectDate(final View view) {
		final AlertDialog.Builder dateDialog = new AlertDialog.Builder(this);

		LayoutInflater inflater = getLayoutInflater();
		final View dialogView = inflater.inflate(R.layout.date_change_dialog, null);
		dateDialog.setView(dialogView);
		dateDialog.setTitle("Select a date:");

		final DatePicker datePicker = (DatePicker) dialogView.findViewById(R.id.movieDatePicker);

		// Set the date in the date picker to the previous selected date.
		String date = (view.getTag().equals("start_date")) ? startDate : finishDate;
		if (date != null && !date.isEmpty()) {
			try {
				SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy");
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(simpleDateFormat.parse(date));
				datePicker.updateDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}

		dateDialog.setPositiveButton("Save", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// Get the date from the DatePicker.
				SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy");
				Calendar calendar = Calendar.getInstance();
				calendar.set(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth());
				String dateFormat = simpleDateFormat.format(calendar.getTime());

				// Save the date to the database and update the view
				ContentValues movieValues = new ContentValues();

				if(view.getTag().equals("start_date")) {
					movieValues.put(MovieDatabaseHelper
							.COLUMN_PERSONAL_START_DATE, dateFormat);

					Button button = (Button) findViewById(R.id.startDateButton);
					button.setText(dateFormat);
					movieStartDate.setText(getString(R.string.change_start_date_2) +
							dateFormat);
					startDate = dateFormat;

				} else {
					movieValues.put(MovieDatabaseHelper
							.COLUMN_PERSONAL_FINISH_DATE, dateFormat);

					Button button = (Button) findViewById(R.id.endDateButton);
					button.setText(dateFormat);
					movieFinishDate.setText(getString(R.string.change_finish_date_2)
							+ dateFormat);
					finishDate = dateFormat;
				}

				database = databaseHelper.getWritableDatabase();
				databaseHelper.onCreate(database);
				database.update(MovieDatabaseHelper.TABLE_MOVIES, movieValues,
						MovieDatabaseHelper.COLUMN_MOVIES_ID + "=" + movieId, null);
				dialog.dismiss();
			}
		});

		dateDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
			}
		});

		dateDialog.show();
	}

	private void fadeOutAndHideAnimation(final View view) {
		Animation fadeOut = new AlphaAnimation(1, 0);
		fadeOut.setInterpolator(new AccelerateInterpolator());
		fadeOut.setDuration(100);

		view.startAnimation(fadeOut);
	}

	private void fadeInAndShowAnimation(final View view) {
		Animation fadeIn = new AlphaAnimation(0, 1);
		fadeIn.setInterpolator(new AccelerateInterpolator());
		fadeIn.setDuration(100);

		fadeIn.setAnimationListener(new Animation.AnimationListener() {
			public void onAnimationEnd(Animation animation) {
				view.setVisibility(View.VISIBLE);
			}
			public void onAnimationRepeat(Animation animation) {}
			public void onAnimationStart(Animation animation) {}
		});

		view.startAnimation(fadeIn);
	}

	private NotifyingScrollView.OnScrollChangedListener 
			mOnScrollChangedListener = new NotifyingScrollView
			.OnScrollChangedListener() {
		public void onScrollChanged(ScrollView scrollView,
				int l, int t, int oldl, int oldt) {
			final int headerHeight = findViewById(R.id.movieImage).getHeight() - 
					toolbar.getHeight();
			final float ratio = (float) Math.min(Math.max(t, 0),
					headerHeight) / headerHeight;
			final int newAlpha = (int) (ratio * 255);
			mToolbarBackgroundDrawable.setAlpha(newAlpha);

			// 256 because otherwise it'll become invisible when newAlpha is 255.
			alphaForegroundColorSpan.setAlpha(256 - newAlpha);
			showTitle.setSpan(alphaForegroundColorSpan, 0, showTitle.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			getSupportActionBar().setTitle(showTitle);
		}
	};

	private Drawable.Callback drawableCallback = new Drawable.Callback() {
		@Override
		public void invalidateDrawable(Drawable drawable) {
			toolbar.setBackgroundDrawable(drawable);
		}

		@Override
		public void scheduleDrawable(Drawable drawable, Runnable runnable, long when) {}

		@Override
		public void unscheduleDrawable(Drawable drawable, Runnable runnable) {}
	};

	// Load the list of actors.
	private class CastList extends AsyncTask<String, Void, String> {

		private final String API_KEY = ConfigHelper.getConfigValue(
				getApplicationContext(), "api_key");

		protected String doInBackground(String ... params) {
			String line;
			StringBuilder stringBuilder = new StringBuilder();

			String movie = (isMovie) ? "movie" : "tv";
			
			// Load the list with actors that played in the movie.
			try {
				URL url = new URL("https://api.themoviedb.org/3/" + movie + "/" + 
						movieId + "/credits?api_key=" + API_KEY + 
						getLanguageParameter());
				URLConnection urlConnection = url.openConnection();

				try {
					BufferedReader bufferedReader = new BufferedReader(
							new InputStreamReader(
							urlConnection.getInputStream()));

					// Create one long string of the webpage.
					while((line = bufferedReader.readLine()) != null) {
						stringBuilder.append(line).append("\n");
					}

					// Close connection and return the data from the webpage.
					bufferedReader.close();
					return stringBuilder.toString();
				} catch(IOException ioe) {
					ioe.printStackTrace();
				}
			} catch(MalformedURLException mue) {
				mue.printStackTrace();
			} catch(IOException ioe) {
				ioe.printStackTrace();
			}

			// Loading the dataset failed, return null.
			return null;
		}

		protected void onPostExecute(String response) {
			if (response != null && !response.isEmpty()) {
				// Set all the actors in a list and send that to the adapter.
				try {
					JSONObject reader = new JSONObject(response);

					// Add the cast to the castView
					if (reader.getJSONArray("cast").length() <= 0) {
						// This movie has no available cast,
						// do not show the cast related views.
						TextView textView = (TextView)
								mActivity.findViewById(R.id.castTitle);
						View view = mActivity.findViewById(R.id.secondDivider);

						textView.setVisibility(View.GONE);
						view.setVisibility(View.GONE);
						castView.setVisibility(View.GONE);
					} else {
						JSONArray castArray = reader.getJSONArray("cast");

						for (int i = 0; i < castArray.length(); i++) {
							JSONObject castData = castArray.getJSONObject(i);
							castArrayList.add(castData);
						}
						castAdapter = new CastBaseAdapter(castArrayList,
								getApplicationContext());

						castView.setAdapter(castAdapter);
					}

					// Add the crew to the crewView
					if (reader.getJSONArray("crew").length() <= 0) {
						// This movie has no available cast,
						// do not show the cast related views.
						TextView textView = (TextView)
								mActivity.findViewById(R.id.crewTitle);
						View view = mActivity.findViewById(R.id.thirdDivider);

						textView.setVisibility(View.GONE);
						view.setVisibility(View.GONE);
						crewView.setVisibility(View.GONE);
					} else {
						JSONArray crewArray = reader.getJSONArray("crew");

						for (int i = 0; i < crewArray.length(); i++) {
							JSONObject crewData = crewArray.getJSONObject(i);

							// Before adding the JSONObject to the Array,
							// "camouflage" it as an actor so it can use
							// the CastBaseAdapter
							crewData.put("character", crewData.getString("job"));

							crewArrayList.add(crewData);
						}

						crewAdapter = new CastBaseAdapter(crewArrayList,
								getApplicationContext());

						crewView.setAdapter(crewAdapter);
					}
				} catch (JSONException je) {
					je.printStackTrace();
				}
			} else {
				Toast.makeText(getApplicationContext(), getApplicationContext().getResources()
						.getString(R.string.no_internet_connection), Toast.LENGTH_SHORT).show();
			}
		}
	}

	// Load a list with similar movies.
	private class SimilarMovieList extends AsyncTask<String, Void, String> {

		private final String API_KEY = ConfigHelper.getConfigValue(
				getApplicationContext(), "api_key");

		protected String doInBackground(String ... params) {
			String line;
			StringBuilder stringBuilder = new StringBuilder();

			String movie = (isMovie) ? "movie" : "tv";
			
			// Load the webpage with the list of similar movies.
			try {
				URL url = new URL("https://api.themoviedb.org/3/" + movie + "/" +
						movieId + "/similar?api_key=" + 
						API_KEY + getLanguageParameter());
				URLConnection urlConnection = url.openConnection();

				try {
					BufferedReader bufferedReader = new BufferedReader(
							new InputStreamReader(
							urlConnection.getInputStream()));

					// Create one long string of the webpage.
					while((line = bufferedReader.readLine()) != null) {
						stringBuilder.append(line).append("\n");
					}

					// Close connection and return the data from the webpage.
					bufferedReader.close();
					return stringBuilder.toString();
				} catch(IOException ioe) {
					ioe.printStackTrace();
				}
			} catch(MalformedURLException mue) {
				mue.printStackTrace();
			} catch(IOException ioe) {
				ioe.printStackTrace();
			}

			// Loading the dataset failed, return null.
			return null;
		}

		protected void onPostExecute(String response) {
			if (response != null && !response.isEmpty()) {
				// Set all the similar movies in a list and send that to the adapter.
				try {
					JSONObject reader = new JSONObject(response);
					JSONArray similarMovieArray = reader.getJSONArray("results");
					for (int i = 0; i < similarMovieArray.length(); i++) {
						JSONObject movieData = similarMovieArray.getJSONObject(i);
						similarMovieArrayList.add(movieData);
					}
					similarMovieAdapter = new SimilarMovieBaseAdapter(
							similarMovieArrayList, getApplicationContext());

					similarMovieView.setAdapter(similarMovieAdapter);
				} catch (JSONException je) {
					je.printStackTrace();
				}
			} else {
				Toast.makeText(getApplicationContext(), getApplicationContext().getResources()
						.getString(R.string.no_internet_connection), Toast.LENGTH_SHORT).show();
			}
		}
	}

	// Load the movie details.
	private class MovieDetails extends AsyncTask<String, Void, String> {

		private final String API_KEY = ConfigHelper.getConfigValue(
				getApplicationContext(), "api_key");
		private boolean missingOverview;

		protected String doInBackground(String... params) {
			if(params.length > 0) {
				missingOverview = params[0].equalsIgnoreCase("true");
			}

			String line;
			StringBuilder stringBuilder = new StringBuilder();

			// Load the movie webpage (and check for updates/corrections).
			try {
				String type = (isMovie) ? "movie" : "tv";
				URL url;
				if(missingOverview) {
					url = new URL("https://api.themoviedb.org/3/" + type + 
							"/" + movieId + "?api_key=" + API_KEY);
				} else {
					url = new URL("https://api.themoviedb.org/3/" + type + 
							"/" + movieId + "?api_key=" + API_KEY 
							+ getLanguageParameter());
				}
				URLConnection urlConnection = url.openConnection();

				try {
					BufferedReader bufferedReader = new BufferedReader(
						new InputStreamReader(
						urlConnection.getInputStream()));

					// Create one long string of the webpage.
					while((line = bufferedReader.readLine()) != null) {
						stringBuilder.append(line).append("\n");
					}

					// Close connection and return the data from the webpage.
					bufferedReader.close();
					return stringBuilder.toString();
				} catch(IOException ioe) {
					ioe.printStackTrace();
				}
			} catch(MalformedURLException mue) {
				mue.printStackTrace();
			} catch(IOException ioe) {
				ioe.printStackTrace();
			}

			// Loading the dataset failed, return null.
			return null;
		}

		protected void onPostExecute(String response) {
			if (response != null && !response.isEmpty()) {
				// Send the dataset to setMovieData to change the data where needed.
				try {
					JSONObject movieData = new JSONObject(response);
					// If the translation is missing, only change the overview.
					// Doing this with setMovieData would change everything to English.
					// To prevent that, we use this if-statement.
					if (missingOverview) {
						movieDescription.setText(movieData.getString("overview"));
					} else {
						setMovieData(movieData);
					}
				} catch (JSONException e) {
					e.printStackTrace();
				}
			} else {
				Toast.makeText(getApplicationContext(), getApplicationContext().getResources()
						.getString(R.string.no_internet_connection), Toast.LENGTH_SHORT).show();
			}
		}
	}

	@SuppressLint("ParcelCreator")
	/* Credits to: Flavien Laurent (http://flavienlaurent.com/blog/2013/11/20/making-your-action-bar-not-boring/) */
	public class AlphaForegroundColorSpan extends ForegroundColorSpan {
		private float mAlpha;

		public AlphaForegroundColorSpan(int color) {
			super(color);
		}

		public AlphaForegroundColorSpan(Parcel src) {
			super(src);
			mAlpha = src.readFloat();
		}

		public void writeToParcel(Parcel dest, int flags) {
			super.writeToParcel(dest, flags);
			dest.writeFloat(mAlpha);
		}

		@Override
		public void updateDrawState(TextPaint ds) {
			ds.setColor(getAlphaColor());
		}

		public void setAlpha(float alpha) {
			mAlpha = alpha;
		}

		public float getAlpha() {
			return mAlpha;
		}

		private int getAlphaColor() {
			int foregroundColor = getForegroundColor();
			return Color.argb((int) (mAlpha * 255), Color.red(foregroundColor), Color.green(foregroundColor), Color.blue(foregroundColor));
		}
	}
}
